////////////////////////////////////////////////////////////////////////////////
// Filename: DirectX_10_Model.cpp
////////////////////////////////////////////////////////////////////////////////
#include "DirectX_10_Model.h"

using namespace Omen;

DirectX_10_Model::DirectX_10_Model()
{
    m_vertexBuffer = 0;
    m_indexBuffer = 0;
    m_pTexture = 0;
    m_model = 0;
}


DirectX_10_Model::DirectX_10_Model(const DirectX_10_Model& other)
{
}


DirectX_10_Model::~DirectX_10_Model()
{
}


bool DirectX_10_Model::Initialize( ID3D10Device* device, const WCHAR* modelFilename, const WCHAR* textureFilename)
{
    bool result;

    // Load in the model data.
    result = LoadModel(modelFilename);
    if(!result)
    {
        return false;
    }

    // Initialize the vertex and index buffer that hold the geometry for the triangle.
    result = InitializeBuffers(device);
    if(!result)
    {
        return false;
    }

    // Load the texture for this model.
    result = LoadTexture(device, textureFilename);
    if(!result)
    {
        return false;
    }

    return true;
}


void DirectX_10_Model::Shutdown()
{
    // Release the model texture.
    ReleaseTexture();

    // Release the vertex and index buffers.
    ShutdownBuffers();

    // Release the model data.
    ReleaseModel();

    return;
}


void DirectX_10_Model::Render( ID3D10Device* device)
{
    // Put the vertex and index buffers on the graphics pipeline to prepare them for drawing.
    RenderBuffers(device);

    return;
}


int DirectX_10_Model::GetIndexCount()
{
    return m_indexCount;
}


ID3D10ShaderResourceView* DirectX_10_Model::GetTexture()
{
    return m_pTexture->GetTexture();
}


bool DirectX_10_Model::InitializeBuffers( ID3D10Device* device)
{
    VertexType* vertices;
    unsigned long* indices;
    D3D10_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
    D3D10_SUBRESOURCE_DATA vertexData, indexData;
    HRESULT result;
    int i;

    
    // Create the vertex array.
    vertices = new VertexType[m_vertexCount];
    if(!vertices)
    {
        return false;
    }

    // Create the index array.
    indices = new unsigned long[m_indexCount];
    if(!indices)
    {
        return false;
    }

    // Load the vertex array and index array with data.
    for( i=0; i<m_vertexCount; i++)
    {
        vertices[i].position = D3DXVECTOR3(m_model[i].x, m_model[i].y, m_model[i].z);
        vertices[i].texture =  D3DXVECTOR2(m_model[i].tu, m_model[i].tv);
        vertices[i].normal =   D3DXVECTOR3(m_model[i].nx, m_model[i].ny, m_model[i].nz);

        indices[i] = i;
    }

    // Set up the description of the vertex buffer.
    vertexBufferDesc.Usage      = D3D10_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth  = sizeof(VertexType) * m_vertexCount;
    vertexBufferDesc.BindFlags  = D3D10_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags  = 0;

    // Give the subresource structure a pointer to the vertex data.
    vertexData.pSysMem = vertices;

    // Now finally create the vertex buffer.
    result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer);
    if(FAILED(result))
    {
        return false;
    }

    // Set up the description of the index buffer.
    indexBufferDesc.Usage           = D3D10_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth       = sizeof(unsigned long) * m_indexCount;
    indexBufferDesc.BindFlags       = D3D10_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags  = 0;
    indexBufferDesc.MiscFlags       = 0;

    // Give the subresource structure a pointer to the index data.
    indexData.pSysMem = indices;

    // Create the index buffer.
    result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
    if(FAILED(result))
    {
        return false;
    }

    // Release the arrays now that the vertex and index buffers have been created and loaded.
    delete [] vertices;
    vertices = 0;

    delete [] indices;
    indices = 0;

    return true;
}


void DirectX_10_Model::ShutdownBuffers()
{
    // Release the index buffer.
    if(m_indexBuffer)
    {
        m_indexBuffer->Release();
        m_indexBuffer = 0;
    }

    // Release the vertex buffer.
    if(m_vertexBuffer)
    {
        m_vertexBuffer->Release();
        m_vertexBuffer = 0;
    }

    return;
}


void DirectX_10_Model::RenderBuffers( ID3D10Device* device)
{
    unsigned int stride;
    unsigned int offset;


    // Set vertex buffer stride and offset.
    stride = sizeof(VertexType); 
    offset = 0;
    
    // Set the vertex buffer to active in the input assembler so it can be rendered.
    device->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);

    // Set the index buffer to active in the input assembler so it can be rendered.
    device->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
    device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    return;
}


bool DirectX_10_Model::LoadTexture( ID3D10Device* device, const WCHAR* filename)
{
    bool result;


    // Create the texture object.
    m_pTexture = new DirectX_10_Texture;

    if(!m_pTexture)
    {
        return false;
    }

    // Initialize the texture object.
    result = m_pTexture->Initialize(device, filename);
    if(!result)
    {
        return false;
    }

    return true;
}


void DirectX_10_Model::ReleaseTexture()
{
    // Release the texture object.
    if(m_pTexture)
    {
        m_pTexture->Shutdown();
        delete m_pTexture;
        m_pTexture = 0;
    }

    return;
}


bool DirectX_10_Model::LoadModel(const WCHAR* filename)
{
    ifstream fin;
    char input;
    int i;


    // Open the model file.
    fin.open(filename);
    
    // If it could not open the file then exit.
    if(fin.fail())
    {
        return false;
    }

    // Read up to the value of vertex count.
    fin.get(input);
    while(input != ':')
    {
        fin.get(input);
    }

    // Read in the vertex count.
    fin >> m_vertexCount;

    // Set the number of indices to be the same as the vertex count.
    m_indexCount = m_vertexCount;

    // Create the model using the vertex count that was read in.
    m_model = new ModelType[m_vertexCount];
    if(!m_model)
    {
        return false;
    }

    // Read up to the beginning of the data.
    fin.get(input);
    while(input != ':')
    {
        fin.get(input);
    }
    fin.get(input);
    fin.get(input);

    // Read in the vertex data.
    for( i=0; i<m_vertexCount; i++)
    {
        fin >> m_model[i].x >> m_model[i].y >> m_model[i].z;
        fin >> m_model[i].tu >> m_model[i].tv;
        fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz;
    }

    // Close the model file.
    fin.close();

    return true;
}


void DirectX_10_Model::ReleaseModel()
{
    if(m_model)
    {
        delete [] m_model;
        m_model = 0;
    }

    return;
}